package com.computer.spring.framework.webmvc;

import com.computer.spring.framework.annotation.BYRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description
 * @Author MagicIce
 * @Date 2020/11/22 9:40
 */
public class BYHandlerAdapter {

    public boolean supports(Object handler){
        return handler instanceof BYHandlerMapping;
    }

    public BYModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        BYHandlerMapping handlerMapping = (BYHandlerMapping) handler;
        //  每个方法有一个参数列表，这里保存的是形参列表
        Map<String, Integer> paramMapping = new HashMap<>();
        //  这里只是给出命名参数
        Annotation[][] pa = handlerMapping.getMethod().getParameterAnnotations();
        for (int i = 0; i < pa.length; i++) {
            for (Annotation annotation : pa[i]){
                if (annotation instanceof BYRequestParam){
                    String paramName = ((BYRequestParam) annotation).value();
                    if (!"".equals(paramName.trim())){
                        paramMapping.put(paramName, i);
                    }
                }
            }
        }

        /**
         * 根据用户请求的参数信息，跟 Method 中的参数信息进行动态匹配
         * response 传进来的目的只有一个：将其复制给方法参数，仅此而已
         *
         * 只有当用户传过来的 ModelAndView 为空的时候，才会新建一个默认的
         *
         * 1、要准备好这个方法的形参列表
         * 方法重载时，形参的决定因素：参数的个数、参数的类型、参数顺序、方法的名字
         */
        Class<?>[] paramTypes = handlerMapping.getMethod().getParameterTypes();
        for (int i = 0; i < paramTypes.length; i++) {
            Class<?> type = paramTypes[i];
            if (type == HttpServletRequest.class || type == HttpServletResponse.class){
                paramMapping.put(type.getName(), i);
            }
        }

        /**
         * 2、得到自定义命名参数所在的位置
         * 用户通过 URL 传过来的参数列表
         */
        Map<String, String[]> requestParameterMap = request.getParameterMap();

        /** 3、构造实参列表 */
        Object[] paramValues = new Object[paramTypes.length];

        for (Map.Entry<String, String[]> param : requestParameterMap.entrySet()){
            String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll("\\s", "");
            if (!paramMapping.containsKey(param.getKey())){
                continue;
            }
            int index = paramMapping.get(param.getKey());
            /** 参数的类型转换 */
            paramValues[index] = caseStringValue(value, paramTypes[index]);
        }

        if (paramMapping.containsKey(HttpServletRequest.class.getName())){
            int requestIndex = paramMapping.get(HttpServletRequest.class.getName());
            paramValues[requestIndex] = request;
        }

        if (paramMapping.containsKey(HttpServletResponse.class.getName())){
            int requestIndex = paramMapping.get(HttpServletResponse.class.getName());
            paramValues[requestIndex] = response;
        }

        /** 取出 Controller、Method，利用反射机制进行调用 */
        Object result = handlerMapping.getMethod().invoke(handlerMapping.getController(), paramValues);

        if (null == result){
            return null;
        }

        boolean isModelAndView = handlerMapping.getMethod().getReturnType() == BYModelAndView.class;
        if (isModelAndView){
            return (BYModelAndView) result;
        }else {
            return null;
        }
    }

    private Object caseStringValue(String value, Class<?> clazz) {
        if (clazz == String.class){
            return value;
        }else if (clazz == Integer.class){
            return Integer.valueOf(value);
        }else if (clazz == int.class){
            return Integer.valueOf(value).intValue();
        }else {
            return null;
        }
    }
}
